#include "posets.h"
#include "contexts.h"
#include "commondefs.h"
#include "debug.h"

#include "algo1110.h"

#define CTXALGO1110SEP ""

static void set_mi_names(Context *context, Poset * p);
static void set_ji_names(Context *context, Poset * p);

/** Listing 11-10 from Free Lattices. 
    This algorithm takes a context and 
    produces its context lattice 
    (or Galois lattice)
*/ 
Poset * algo1110(Context *context)
{
  Poset * ret=NEW(Poset);

  int ji,mi; 
  /**< indexes to join-meet irreducibles */
  
  int no_mis = ctx_no_mi(context);
  /**<   Cardinality of the underlying set: */
  /*    it is the set of all meet irreducible elements */

  struct lnode * index;

  Listofsss sss_S, sss_T,current;
  /**< Three posets */
  
  Subset ss_all_mis,ss_D;
  /**< Two subsets */

  /** Intialize the subset of all_mis to contain all the mi */
  ss_total(no_mis,&ss_all_mis); 
/*   ss_set_name(&ss_all_mis,"b");  */

  /** The posets are initialized to be empty  */
  sss_S=sss_T=current=NULL;

  /** The poset S contains the set of all meet irreducible els */
  sss_S = list_add_element(ss_all_mis,sss_S);
  
  /**  For every join irredducible */
  FORALLJIIN(ji,context)
    {
      /**   T is empty */
      sss_T = NULL;
      
      /**  for all elements in S */
      FORALLIN(current,sss_S)
	{
	  /** The subset D is an empty set of meets */
	  ss_empty(no_mis,&ss_D);
	  
	  /** if mi is a meet irreducible in the current closed  
	      such that ji I mi, 
	      then add it to the subset D */
	  FORALLMIIN(mi,context)
	    {
	      if(ss_belongs(mi,&current->el)
		 && ctx_orthogonal(context,ji,mi))
		ss_addto(&ss_D,mi) ;
	    }
	  
	  /** 
	      If D is the image of a join irreducible,
	      set its name to the name of the join irreducible
	  */
	  
	  /**  If the subset D is new -- 
	       that is, not alredy in T or S --
	       then add it to the poset T */
	  if((index=list_find(ss_D,sss_T,ss_equal)))
	    {
/* 	      if(ss_equal(&current->el,&ss_all_mis)) */
/* 		ss_add_name(&index->el,ctx_ji_name(context,ji),CTXALGO1110SEP); */
	    }
	  else
	    {
	      if((index=list_find(ss_D,sss_S,ss_equal)))
		{
/* 		  if(ss_equal(&current->el,&ss_all_mis)) */
/* 		    ss_add_name(&index->el,ctx_ji_name(context,ji),CTXALGO1110SEP); */
		}
	      else
		{
/* 		  if(ss_equal(&current->el,&ss_all_mis)) */
/* 		   ss_add_name(&ss_D,ctx_ji_name(context,ji),CTXALGO1110SEP); */
		  sss_T = list_add_element(ss_D,sss_T);
		}
	    }
	}
      /** The poset S is now the union of the previous S and T */
      sss_S = list_concatenate(sss_S,sss_T);
    }

  poset_set_name(ctx_name(context),ret);
  ret->sss = sss_S;

  set_ji_names(context,ret);
  set_mi_names(context,ret);

  poset_force_opposite(ret); 
  
  return ret;
}


/** Problem : is there an efficient way to do that ?? */

void set_mi_names(Context *context, Poset * p)
{
  int mi;
  struct lnode *index;
  Subset  *ss_mi;
  
  FORALLMIIN(mi,context)
    {
      /** Construct the closure of mi */ 
      ss_mi = ctx_mi_closure(context,mi);
      
      /* Find the closure of mi in p->sss */
      if( (index=list_find(*ss_mi,p->sss,ss_equal)) )
	ss_add_name(&index->el,ctx_mi_name(context,mi),CTXALGO1110SEP);
      
      free(ss_mi);
    }
  
}

void set_ji_names(Context *context, Poset * p)
{
  int ji;
  struct lnode *index;
  Subset  *ss_mi;
  
  FORALLJIIN(ji,context)
    {
      /** Construct the closure of mi */ 
      ss_mi = ctx_ji_image(context,ji);
      
      /* Find the closure of mi in p->sss */
      if( (index=list_find(*ss_mi,p->sss,ss_equal)) )
	ss_add_name(&index->el,ctx_ji_name(context,ji),CTXALGO1110SEP);
      
      free(ss_mi);
    }
}

